home *** CD-ROM | disk | FTP | other *** search
- 15-Nov-87 22:41:42-MST,9407;000000000000
- Date: Thursday, 21 August 1986 01:45-MDT
- From: Phil Karn <karn at ka9q.bellcore.COM>
- To: info-hams
- Re: Controlling ICOM radios from the IBM PC - Part 2 (source code)
-
- Here's the source code I wrote for controlling the ICOM radios through my PC
- clone's printer port. Note that all frequencies are represented in hertz,
- using longs; this makes things more consistent since different radio functions
- require different precision.
-
- -----------
- /* icom.c
- * Library functions for driving the ICOM computer interface
- * Copyright 1986 by Phil Karn, KA9Q
- * Permission granted for free noncommercial copying and use by
- * licensed radio amateurs.
- */
- #include "icom.h"
-
- char *modes[] = {
- "LSB", /* 0 */
- "USB", /* 1 */
- "AM", /* 2 */
- "CW", /* 3 */
- "RTTY", /* 4 */
- "FM", /* 5 */
- "CW Narrow", /* 6 */
- "RTTY Narrow", /* 7 */
- "lsb", /* 8 */
- "usb", /* 9 */
- "am", /* a */
- "cw narrow", /* b */
- "rtty narrow", /* c */
- "fm", /* d */
- "0xe", /* e */
- "0xf" /* f */
- };
-
- /* Read band */
- int
- read_band(freq,lower,upper)
- long freq; /* Used just to select the radio */
- long *lower,*upper; /* Band limits returned through here */
- {
- register int i;
-
- start_cmd();
- if(send_byte(BAND | band(freq)) < 0){
- end_cmd();
- return -1;
- }
- *upper = 0;
- read_byte(); /* Toss opening delim */
- for(i=0;i<6;i++)
- *upper = *upper * 10 + (read_byte() & 0xf);
- read_byte(); /* Toss closing delim */
- *upper *= 10000; /* Convert to hertz */
-
- *lower = 0;
- read_byte(); /* Toss second opening delim */
- for(i=0;i<6;i++)
- *lower = *lower * 10 + (read_byte() & 0xf);
- read_byte(); /* Toss second closing delim */
- *lower *= 10000; /* Convert to hertz */
- end_cmd();
- return 0;
- }
- /* Set frequency; the proper radio is automatically selected */
- int
- set_freq(freq)
- long freq; /* Frequency, hertz */
- {
- register int i;
- char fstr[15];
-
- start_cmd();
- if(send_byte(FREQ | band(freq)) < 0){
- end_cmd();
- return -1;
- }
- send_byte(FREQ | 0xd);
- sprintf(fstr,"%09ld",freq/10);
- for(i=0;i<9;i++)
- send_byte(FREQ | (fstr[i] - '0'));
- send_byte(FREQ | 0xe);
- end_cmd();
- return 0;
- }
-
- /* Read frequency */
- long
- read_freq(freq)
- long freq; /* For band selection only */
- {
- register int i;
-
- start_cmd();
- if(send_byte(FREQ | band(freq)) < 0){
- end_cmd();
- return -1;
- }
- if(read_byte() < 0) /* Discard opening delimiter */
- return -1;
- freq = 0;
- for(i=0;i<9;i++){
- freq = freq * 10 + (read_byte() & 0xf);
- }
- read_byte(); /* Discard closing delimiter */
- freq *= 10;
- end_cmd();
- return freq;
- }
- /* set mode */
- int
- set_mode(freq,mode)
- long freq; /* For radio selection */
- int mode; /* Desired operating mode */
- {
- start_cmd();
- if(send_byte(MODE | band(freq)) < 0){
- end_cmd();
- return -1;
- }
- send_byte(MODE | 0xd);
- send_byte(MODE | mode);
- send_byte(MODE | 0xe);
- end_cmd();
- return 0;
- }
- /* Return current mode */
- int
- read_mode(freq)
- long freq; /* For radio selection */
- {
- int c;
-
- start_cmd();
- if(send_byte(MODE | band(freq)) < 0){
- end_cmd();
- return -1;
- }
- read_byte();
- c = read_byte();
- read_byte();
- end_cmd();
- return c & 0xf;
- }
- /* Set offset */
- int
- set_offset(freq,offset)
- long freq; /* For radio selection */
- long offset; /* Offset, hertz */
- {
- register int i;
- char fstr[15];
-
- start_cmd();
- if(send_byte(OFFSET | band(freq)) < 0){
- end_cmd();
- return -1;
- }
- send_byte(OFFSET | 0xd);
- sprintf(fstr,"%09ld",freq/1000);
- for(i=0;i<9;i++)
- send_byte(OFFSET | (fstr[i] - '0'));
- send_byte(OFFSET | 0xe);
- end_cmd();
- return 0;
- }
-
- /* Read offset */
- long
- read_offset(freq)
- long freq; /* For radio selection */
- {
- register int i;
- long offset;
-
- start_cmd();
- if(send_byte(OFFSET | band(freq)) < 0){
- end_cmd();
- return -1;
- }
- read_byte(); /* Discard opening delimiter */
- offset = 0;
- for(i=0;i<9;i++)
- offset = offset * 10 + (read_byte() & 0xf);
- read_byte(); /* Discard closing delimiter */
- offset *= 1000;
- end_cmd();
- return offset;
- }
- /* Select memory channel or vfo */
- int
- set_mem(freq,val)
- long freq; /* For radio selection */
- int val; /* Desired VFO/channel number */
- {
- start_cmd();
- if(send_byte(MEMVFO | band(freq)) < 0){
- end_cmd();
- return -1;
- }
- send_byte(MEMVFO | 0xd);
- send_byte(MEMVFO | ((val >> 4) & 0xf)); /* tens digit */
- send_byte(MEMVFO | (val & 0xf)); /* units digit */
- send_byte(MEMVFO | 0xe);
- end_cmd();
- return 0;
- }
- /* Transfer between VFO and memory */
- int
- transfer(freq,dir)
- long freq; /* For radio selection */
- int dir; /* Desired direction of transfer */
- {
- start_cmd();
- if(send_byte(MEMRW | band(freq)) < 0){
- end_cmd();
- return -1;
- }
- send_byte(MEMRW | 0xd);
- send_byte(MEMRW | dir);
- send_byte(MEMRW | 0xe);
- end_cmd();
- return 0;
- }
- /* Set band
- * Uses the hack by NG6Q in April 1986 Ham Radio
- * Warning: untested (I don't have a 751).
- */
- int
- set_band(freq,b)
- long freq; /* For radio selection */
- int b; /* Desired band */
- {
- long funny;
-
- set_mem(freq,38); /* Select channel 38 */
- funny = (freq/1000000) * 1000000; /* Truncate to Mhz */
- funny += 100000 * b; /* Desired band goes in 100khz digit*/
- set_freq(funny);
- transfer(freq,WRITE); /* Store in memory */
- set_mem(freq,0); /* Go back to VFO */
- transfer(freq,READ); /* Get the funny value */
- set_freq(freq); /* Put in the one we really want */
- return 0;
- }
-
- /* The following are internal subroutines that perform the low-level
- * parts of the host/radio protocol. These can be "static" if you wish.
- */
-
- /* Send individual byte of a message */
- int
- send_byte(c)
- char c;
- {
- register int i;
-
- outportb(I_DATA,c);
-
- /* Turn on WP and output mode in addition to SRQ */
- outportb(I_CTL,CTL_POL^(SRQ_CMD|WP_CMD|OUTPUT_MODE));
-
- /* Wait for DAV to go active low */
- for(i=TIMEOUT;i != 0;i--){
- if((inportb(I_DAV) & DAV_STAT) == 0)
- break;
- }
- if(i == 0){
- outportb(I_CTL,CTL_POL);
- printf("sendbyte fail\n");
- return -1;
- }
- /* Drop WP and output mode, keeping SRQ active */
- outportb(I_CTL,CTL_POL^SRQ_CMD);
-
- /* Wait for DAV to go inactive high */
- for(i=TIMEOUT;i != 0;i--){
- if((inportb(I_DAV) & DAV_STAT) != 0)
- break;
- }
- if(i == 0){
- outportb(I_CTL,CTL_POL);
- printf("sendbyte fail 2\n");
- return -2;
- }
- return 0;
- }
-
- /* Read individual byte within a message */
- int
- read_byte()
- {
- register int i;
- register int c;
-
- /* Configure for input */
- outportb(I_CTL,CTL_POL^(RP_CMD|SRQ_CMD));
-
- /* Wait for DAV to go active low */
- for(i=TIMEOUT;i != 0;i--){
- if((inportb(I_DAV) & DAV_STAT) == 0)
- break;
- }
- if(i == 0){
- outportb(I_CTL,CTL_POL);
- printf("read fail\n");
- return -1;
- }
- /* Read data byte from bus */
- c = inportb(I_DATA);
-
- /* Drop RP, keeping SRQ active */
- outportb(I_CTL,CTL_POL^SRQ_CMD);
-
- /* Wait for DAV to go inactive high */
- for(i=TIMEOUT;i != 0;i--){
- if((inportb(I_DAV) & DAV_STAT) != 0)
- break;
- }
- if(i == 0){
- outportb(I_CTL,CTL_POL);
- printf("read fail 2\n");
- return -2;
- }
- return c & 0xff;
- }
- /* Derive band number from frequency */
- int
- band(freq)
- register long freq;
- {
- if(freq >= 1200000000){
- return MHZ_1200;
- } else if(freq >= 420000000){
- return MHZ_430;
- } else if(freq >= 220000000){
- return MHZ_220;
- } else if(freq >= 140000000){
- return MHZ_144;
- } else if(freq >= 50000000){
- return MHZ_50;
- } else
- return HF;
- }
- /* Begin a message */
- start_cmd()
- {
- /* Assert SRQ */
- outportb(I_CTL,CTL_POL^SRQ_CMD);
- }
- /* End a message */
- end_cmd()
- {
- register int i;
-
- /* Wait a little bit */
- for(i=WAIT;i != 0;i--)
- ;
- /* Deactivate SRQ */
- outportb(I_CTL,CTL_POL);
- }
- -----------------
- /* icom.h
- * Definitions for the ICOM library functions
- * 21 Aug 1986
- * Phil Karn, KA9Q
- */
-
- /* System-dependent constants; edit to taste */
-
- /* Port addresses */
- #define I_DATA 0x3bc /* Data I/O port */
- #define I_CTL 0x3be /* Control port (output) */
- #define I_DAV 0x3bd /* Data available port (input) */
-
- /* Bits within I_DAV */
- #define DAV_STAT 0x40
- #define DAV_POL 0x40 /* DAV is negative polarity */
-
- /* Bits within I_CTL */
- #define OUTPUT_MODE 0x20
- #define RP_CMD 0x8
- #define WP_CMD 0x2
- #define SRQ_CMD 0x1
- /* Specify any bits in I_CTL which are negative logic.
- * Output mode, RP and WP are negative logic; SRQ is positive
- */
- #define CTL_POL (OUTPUT_MODE|RP_CMD|WP_CMD)
-
- /* These two values were found experimentally to work on an 8-MHz 8088
- * Increase WAIT if you get frequent timeouts or protocol lockups
- */
- #define TIMEOUT 65535 /* Timeout on a read/write operation */
- #define WAIT 1100 /* Delay at end of sequence */
-
- /* The following definitions are fixed by the ICOM design; they should not
- * have to be changed.
- */
-
- /* Commands */
- #define BAND 0x10
- #define FREQ 0x20
- #define MODE 0x30
- #define OFFSET 0x40
- #define MEMVFO 0x50
- #define MEMRW 0x60
-
- /* Addresses */
- #define HF 0x1 /* IC-71 or IC-751 */
- #define MHZ_50 0x2
- #define MHZ_144 0x3 /* IC-271 */
- #define MHZ_220 0x4
- #define MHZ_430 0x5 /* IC-471 */
- #define MHZ_1200 0x6 /* IC-1271 */
-
- /* Modes */
- #define LSB 0
- #define USB 1
- #define AM 2
- #define CW 3
- #define RTTY 4
- #define FM 5
- #define CWN 6
- #define RTTYN 7
-
- #define WRITE 1 /* VFO to memory */
- #define READ 2 /* Memory to VFO */
-
- long read_freq();
- --------------
- End of code
-